#pragma once
#include"Log.hpp"
#include<iostream>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/ip.h>
#include<pthread.h>
#include<unistd.h>
#include<cstring>
#include<string.h>

#define BACKLOG 5


class TcpServer {
  private:
    int _listenSock; 
    int _port;
    static TcpServer* _tcpServerPtr;
    TcpServer(int port) : _listenSock(-1), _port(port) {};
    TcpServer(const TcpServer& t) = delete;
    TcpServer& operator=(const TcpServer& t) = delete;
  public:
    static TcpServer* Getinstance(int port) {
      if (nullptr ==  _tcpServerPtr) {
         static pthread_mutex_t _mtx = PTHREAD_MUTEX_INITIALIZER; /*全局锁/静态锁使用宏初始化可以不用手动销毁*/
         pthread_mutex_lock(&_mtx);
         if (nullptr == _tcpServerPtr) {
            _tcpServerPtr = new TcpServer(port); 
            LOG(INFO, "new TcpServer success");
            _tcpServerPtr->InitTcpServer(); 
         }
         pthread_mutex_unlock(&_mtx);
      } 
      return _tcpServerPtr;
    }
  private:
    void InitTcpServer() {
         Sock();
         Bind();
         Listen();
         LOG(INFO, "InitTcpServer success");
    }
    void Sock() {
        _listenSock = socket(AF_INET, SOCK_STREAM, 0); 
        if (_listenSock < 0) {
            LOG(FATAL, "listenSock create error");
            exit(1);
        }
        int opt = 1;
        setsockopt(_listenSock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
        LOG(INFO, "listenSock success && setsockopt");
    }
    void Bind() {
        sockaddr_in local;
        memset(&local, 0, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(_port);
        local.sin_addr.s_addr = INADDR_ANY;
        socklen_t len = sizeof(local); 

        if (bind(_listenSock, (struct sockaddr*)&local, len ) < 0) {
            LOG(FATAL, "bind error");
            exit(2);
        }
        LOG(INFO, "bind success");
    }
    void Listen() {
         int res = listen(_listenSock, BACKLOG); 
         if (res == -1) {
             LOG(FATAL, "listen error");
             exit(3);
         } 
         LOG(INFO, "listen success");
    }
  public:
    int GetListenSock() {
        return _listenSock;
    }
    ~TcpServer() {
      if (_listenSock >= 0) close(_listenSock);
    }
};
TcpServer* TcpServer::_tcpServerPtr = nullptr;
